export default {
    name: "crudtable",
    dependencies: ['./uniedit.js', './UploadDialog.js'], // 依赖声明
    props: {
        //项目
		bgsx: {
            type: Object,
            default: () => {}
		},
        // 表格列配置
		columns: {
			type: Array,
			default: () => []
		},
		// 表单字段配置
		fields: {
			type: Array,
			default: () => [],
			validator: value => value.every(f => f.prop && f.label && f.type)
		},
		// 初始数据
		data: {
			type: Array,
			default: () => []
		},
		viewcolum: {
			type: Array,
			default: () => []
		},
		//分页
        pagination: {
            type: Object,
            default: () => ({
                page: 1,
                size: 15,
                sizes: [10, 20, 50, 100],
                total: 0,
                layout: 'total, sizes, prev, pager, next, jumper'
            })
        },
		// API配置
		api: {
			type: Object,
			default: () => ({
                create: (data) => {},
                update: (data) => {},
                delete: (data) => {}
			})
		},
		//用户id=>name对象
		allusers: {
		    type: Array,
		    default: []
		}
    },
    emits: ['update-data', 'page-change', 'size-change', 'selected-rows', 'sort-change'],
    setup(props, { emit }) {
        const router = VueRouter.useRouter();
        const { smartSpeak } = inject('speech'); //语音
        const tableData = ref([...props.data])
        const dialogVisible = ref(false);
        const dialogApply = ref(false);
        const dialogType = ref('add')
        const formRef = ref(null)
        const formData = reactive({})
        const formRules = reactive({})
        const rowid = ref(); //编辑行id
        const jsonkeys = ref(['muselect', 'checkbox', 'multiimage', 'subtable', 'multifile', 'video', 'area']);
        const columnWidths = ref({});//记忆列宽度
        const printDialogVisible = ref(false); //打印相关
        const currentPrintContent = ref('');
        const printType = ref('');
        const printContent = ref(null);
        const docxContainer = ref(null);
        const errorMessage = ref('');
        const loading = ref(false);
        const isContentLoaded = ref(false);
        const selectedRows = ref([]); // 存储选中的行
        const dialogkb = ref(false);
        const dialogfwb = ref(false);
        const fwbtxt = ref('');
    	const kbcloums = ref({});
    	const kbdata = ref([]);//子表数据详情
        const labelfx = ref(localStorage.getItem('selectedLabel') || 'top');
        const ldoptions = ref({});//联动下拉options
        const user = JSON.parse(localStorage.getItem('user'));
        const currentProcess = ref({currentStep: 0, steps: [], records: []});
        const sortParams = reactive({sortField: '', sortOrder: '', sortType: ''});// 排序参数
        const showUploadDialog = ref({});
        const dialogmap = ref(false);
        const videourl = ref();
        const videoDialogVisible = ref(false); 
        const videoPlayer = ref(null);
        
        // 监听props数据变化
        watch(() => props.data, (newVal) => {
        	tableData.value = newVal ? [...newVal] : [];
        }, {
        	deep: true
        })
        
        // 生成验证规则
        watch(() => props.bgsx, (newVal) => {
            if(newVal?.fields) {
                for (let k in newVal.fields) {
                    formRules[k] = generateRules(newVal.fields[k], false);
                }
            }
        }, {deep: true,immediate: true})
        
        // 行内计算和拼接
        watch(() => formData, (newVal) => {
            calculateFields(newVal, props.bgsx.fields);
        }, { deep: true });
        
        // 关闭窗口要停止视频播放
        watch(() => videoDialogVisible.value, (newValue, oldValue) => {
                if (!newValue && videoPlayer.value) {
                    videoPlayer.value.pause();
                }
            }
        );

    	// 获取组件属性
        const getpath = () => {
            return (props.bgsx?.formname || '').replace(/[\\/:*?"<>|\s]/g, '');
        }
        const getComponentProps = (field) => createGetComponentProps({
            getDisabled: (field) => user.Role != 'admin' && field.edituser?.length > 0 && !field.edituser.includes(user.ID),
            getUploadImgwh: (field) => props.bgsx?.fields?.[field.prop]?.options || '',
            getUploadPath: () => getpath(),
            getRichtextPath: () => getpath()
        })(field, formData);
    	
        // 初始化表单数据
        const initFormData = () => {
            props.fields.forEach(field => {
                if (!Object.hasOwn(formData, field.prop)) {
                    formData[field.prop] = getDefaultValue(field);
                }
            })
        }

        // 处理新增
        const handleAdd = () => {
            rowid.value = '';
        	dialogType.value = 'add'
        	Object.assign(formData, {});
            props.fields.forEach(field => {
                formData[field.prop] = getDefaultValue(field)
            })
            formData.cjz = user.ID || null;
            dialogVisible.value = true;
        }
        
        // 处理编辑
        const handleEdit = async(row) => {
            rowid.value = row.id;
        	dialogType.value = 'edit';
            // 初始化表单数据结构
            Object.assign(formData, {});
            props.fields.forEach(field => {
                if (jsonkeys.value.includes(field.type)) {
                    formData[field.prop] = row[field.prop] && window.validators.isJSON(row[field.prop]) ? JSON.parse(row[field.prop]) : [];
                } else {
                    formData[field.prop] = row[field.prop] || '';
                }
            });
            formData.cjz = row.cjz ? Number(row.cjz) : null;
            await nextTick();
        	dialogVisible.value = true;
        }
        
        // 处理删除
        const handleDelete = async (row) => {
            try {
                smartSpeak('确定删除吗')
                await ElMessageBox.confirm(' 您确定要删除这条数据吗？', '删除确认', {
                    confirmButtonText: '确定',
                    cancelButtonText: '取消',
                    type: 'warning'
                }); 
                await props.api.delete({  id: props.bgsx.id,  ids: [row.id] });
                tableData.value  = tableData.value.filter(item  => item.id  !== row.id); 
                emit('update-data');
            } catch (error) {
                if (error === 'cancel') {
                    return;  // 用户点击了取消，不进行处理
                }
                console.error(' 删除失败:', error);
                ElMessage.error(' 删除失败，请稍后再试');
                smartSpeak('删除失败')
            }
        };
    
    	// 提交表单
    	const submitForm = _.debounce(async() => {
            await formRef.value.validate()
            const processedData = processFormData(formData)
            const apiMethod = dialogType.value === 'add' ? props.api.create : props.api.update
            const res = await apiMethod({
				tid: rowid.value || 0,
				id: props.bgsx.id,
				row: processedData
			})
            emit('update-data');
            dialogVisible.value = false
            ElMessage.success('保存成功')
    	}, 500);
    	
        // 提交数据处理
        const processFormData = (rawData) => {
            const data = { ...rawData }
            props.fields.forEach(field => {
                if (jsonkeys.value.includes(field.type)) {
					if (Array.isArray(data[field.prop])) {
					    data[field.prop] = JSON.stringify(data[field.prop]); //防止json转换乱
					}
				}
                // 处理身份证号去除空格
                if (field.type === 'idcard') {
                    data[field.prop] = data[field.prop]?.replace(/\s/g, '')
                }
                // 处理数字类型转换
                if (field.type === 'number') {
                    data[field.prop] = data[field.prop]?.toString() || '';
                }
                if (field.type == 'date' && field.prop == 'reservation_date' && data.reservation_date) {
                    data.reservation_date =  window.validators.formatDate(data.reservation_date, 'YYYY-MM-DD');//预约日期强制转字符
                }
                data[field.prop] = data[field.prop] || ''; //防止空值undefined不更新
            })
            data.cjz = data.cjz ? Number(data.cjz) : 0;
            return data
        }
        
        // 身份证识别功能
        const scanIdCard = _.debounce(async(fieldKey) => {
            try {
                const input = document.createElement('input')
                input.type = 'file'
                input.accept = 'image/*'
                input.onchange = async (e) => {
                    const file = e.target.files[0]
                    if (file) {
                        const formData = new FormData();
                        formData.append('file', file);
                        const res = await axios.post('/v1/uploadsfz', formData);
                        handleIdCardResult(res.data?.result?.words_result, fieldKey);
                    }
                }
                input.click();
            } catch (err) {
                ElMessage.error('身份证识别失败')
                smartSpeak('身份证识别失败')
            }
        }, 200);
        
        // 身份证自动填充逻辑
        const handleIdCardResult = (data, fieldKey) => {
            if(!data) return;
            console.log(data);
            const fieldConfig = props.fields.find(f => f.prop === fieldKey)
            if (!fieldConfig?.sfzoptions) return
            const mapping = {
                '公民身份号码': fieldKey,
                '姓名': fieldConfig.sfzoptions.name,
                '性别': fieldConfig.sfzoptions.sex,
                '民族': fieldConfig.sfzoptions.mz,
                '出生': fieldConfig.sfzoptions.day,
                '住址': fieldConfig.sfzoptions.ade
            }
            Object.entries(mapping).forEach(([srcKey, targetKey]) => {
                if (targetKey && data[srcKey]) {
                    formData[targetKey] = data[srcKey].words.toString();
                }
            })
            if(formData[fieldKey]) handleIdCardInput(formData[fieldKey], fieldKey)
        }
    
        // 身份证输入处理
        const handleIdCardInput = (value, fieldKey) => {
            if (value.length === 18) {
            	const info = extractIdCardInfo(value)
            	const fieldConfig = props.fields.find(f => f.prop === fieldKey)
            	// 自动填充关联字段
            	if (fieldConfig?.sfzoptions) {
                    nextTick(() => {
                        if (fieldConfig.sfzoptions.sex) {
                        	formData[fieldConfig.sfzoptions.sex] = info.gender
                        }
                        if (fieldConfig.sfzoptions.day) {
                        	formData[fieldConfig.sfzoptions.day] = info.birthdate
                        }
                        if (fieldConfig.sfzoptions.old) {
                        	formData[fieldConfig.sfzoptions.old] = info.old
                        }
                    })
                }
        	}
        }
        
        const handleBeforeUpload = (file, field) => {
            const isImage = file.type.startsWith('image/')
            if (!isImage) {
                ElMessage.error('只能上传图片文件')
                smartSpeak('只能上传图片文件')
                return false
            }
            if (['image', 'sczs'].includes(field.type) && formData[field.prop]?.length >= 1) {
                ElMessage.error('只能上传一张图片')
                smartSpeak('只能上传一张图片')
                return false
            }
            return true
        }
    
        // 图片视频附件上传处理
        const handleUploadSuccess = (response, field) => {
            if (!response.data) return
            const url = response.data
            if (['image', 'sczs', 'file'].includes(field.type)) {
                formData[field.prop] = url;
            } else {
                if (!Array.isArray(formData[field.prop])) {
                	formData[field.prop] = [];
                }
                formData[field.prop].push(url);
        	}
        }
		
    	// 处理文件删除
    	const handleRemove = (file, field) => {
            if (['image', 'sczs', 'file'].includes(field.type)) {
            	formData[field.prop] = '';
            } else if(field.type == 'multifile'){
                formData[field.prop].splice(file, 1); //file为index
            } else {
            	const index = formData[field.prop].findIndex(url => url === file.url)
            	if (index > -1) {
            		formData[field.prop].splice(index, 1)
            	}
            }
        }
		
        // 文件列表转换器
        const getFileList = (field) => {
            return computed(() => {
                const value = formData?.[field.prop]
                if (['image', 'sczs'].includes(field.type)) {
                    return value ? [{uid: '-1', name: field.prop, url: value, status: 'success' }] : [];
                }
                return value?.map(url => ({ name: field.prop, url })) || [];
            }).value;
        }
		
        const getFieldType = (col) => {
            if (col.type) return col.type;
            const field = props.fields.find(f => f.prop === col.prop)
            return field?.type || 'text'
        }
        
        // 解锁
        const handleUnlock = _.debounce(async(id) => {
			if (!id) return;
			await unlockeapi({id: id, tablename: props.bgsx.tablename});
			ElMessage.success('解锁成功');
			emit('update-data');
        }, 300);
        
		// 分页处理逻辑
		const handlePageChange = (page) => {
			emit('page-change', page);
		}

		const handleSizeChange = (size) => {
			emit('size-change', size);
		}
		
        // 列宽计算
        const getColumnWidth = (col) => {
            if (col.width) return col.width;
            //检查是否有缓存
            const savedColumnWidths = localStorage.getItem('columnWidths');
            let savewidth = savedColumnWidths ? JSON.parse(savedColumnWidths)?.[props.bgsx.tablename]?.[col.prop] : null;
            if (savewidth) {
                return savewidth;
            }
            const defaultWidths = {
                image: 120,
                file: 120,
                multiimage: 200,
                multifile: 200,
                date: 150,
                datetime: 180,
                textarea: 240,
                word: 200,
                sczs: 200,
            };
            return defaultWidths[col.type] || null;
        };
        
        // 保存列宽度到本地存储
        const handleHeaderDragEnd = (newWidth, oldWidth, column, event) => {
           if (!columnWidths.value || !columnWidths.value.hasOwnProperty(props.bgsx.tablename)) {
                columnWidths.value[props.bgsx.tablename] = {}; // 如果不存在，则先初始化
            }
            if(column.property) {
                columnWidths.value[props.bgsx.tablename][column.property] = newWidth; // 然后再设置新的宽度
                localStorage.setItem('columnWidths', JSON.stringify(columnWidths.value));
            }
        }
        
        // 打印
		const handlePrint = async (content, type) => {
			try {
				errorMessage.value = '';
				currentPrintContent.value = content;
				printType.value = type;
				isContentLoaded.value = false;
				loading.value = true;
				// 先重置容器引用
				docxContainer.value = null
				// 分步打开弹窗
				printDialogVisible.value = true
				await nextTick() // 等待弹窗开始渲染
				// 添加双重等待确保DOM更新
				await new Promise(resolve => {
					setTimeout(() => {
						requestAnimationFrame(resolve)
					}, 500)
				})
				if (type === 'word') {
    				// 强制获取容器引用
    				if (!docxContainer.value) {
    					docxContainer.value = document.querySelector('.docx-preview')
    				}
    				validateContainer();
					// 获取文档内容
					const response = await fetch(content);
					if (!response.ok) throw new Error('文档加载失败');
					const arrayBuffer = await response.arrayBuffer();
					// 清空容器
					docxContainer.value.innerHTML = '';
					// 渲染文档
					const res = await docx.renderAsync(
						arrayBuffer,
						docxContainer.value,
						null, {
							className: "docx", // 默认样式类名
							inWrapper: false, // 禁用自带容器
							ignoreWidth: false,
							ignoreHeight: false,
							breakPages: true
						}
					);
					// 添加打印样式
					const style = document.createElement('style');
					style.innerHTML = `
			.docx-wrapper {
			  background: white !important;
			  padding: 20px !important;
			}
			.docx > section {
			  margin: 0 auto !important;
			  max-width: 8.5in !important;
			}
		  `;
					docxContainer.value.appendChild(style);
				}

				loading.value = false;
				isContentLoaded.value = true;
			} catch (error) {
				console.error('预览失败:', error);
				loading.value = false;
				errorMessage.value = `文档预览失败：${error.message}`;
			}
		};

		const doPrint = () => {
			nextTick(() => {
				const printWindow = window.open('', '_blank');
				const content = printContent.value.innerHTML;
				console.log(content);
				printWindow.document.write(`
		  <html>
			<head>
			  <title>打印文档</title>
			  <style>
				${docx.defaultStyles}
				body { margin: 0; }
				.docx-wrapper {
				  background: white !important;
				  padding: 20px !important;
				}
				.docx > section {
				  margin: 0 auto !important;
				  max-width: 8.5in !important;
				}
				@media print {
				  .docx p {
					margin: 0 !important;
				  }
				  .docx table {
					page-break-inside: auto !important;
				  }
				  .docx tr {
					page-break-inside: avoid !important;
				  }
				}
			  </style>
			</head>
			<body>
			  ${content}
			  <script>
				window.onload = function() {
				  window.print();
				  setTimeout(() => window.close(), 1000);
				}
			  <\/script>
			</body>
		  </html>
		`);
				printWindow.document.close();
			});
		};
		
		const validateContainer = () => {
			if (!docxContainer.value) {
				console.error('容器元素状态:', {
					exists: !!docxContainer.value,
					visible: docxContainer.value?.offsetParent !== null,
					dimensions: docxContainer.value?.getBoundingClientRect()
				})
				throw new Error('文档容器未找到，当前容器引用: ' + docxContainer.value)
			}
		}
		
        //查看子表
        const ckzb = (k, v) => {
            if(!k || !v) return;
            let value = JSON.parse(v);
            if(value.length > 0){
                kbcloums.value = {};
                let xx = props.bgsx.fields[k].zboptions.map(item => { return item.key });
                for(let v of xx){
                    kbcloums.value[v] = v;
                }
                kbdata.value = value;
                dialogkb.value = true;
            }
        }
        
        //查看富文本
        const ckfwb = (v) => {
            if(!v) return;
            fwbtxt.value = v;
            dialogfwb.value = true;
        }
        
        //子表添加一行
        const addRow = (key, options) => {
            if (typeof key !== 'string' || !Array.isArray(options) || options.length == 0) {
                return;
            }
            let obj = {};
            for (let v of options) {
                obj[v.key] = '';
            }
            if (!Array.isArray(formData[key])) {
                formData[key] = [obj];
            }else{
                formData[key].push(obj);
            }
        }
        
        //子表删除一行
        const DeleteZd = (index, key) => {
            formData[key].splice(index, 1);
        }
        
        const changelabel = (e) => {
            labelfx.value = e;
            localStorage.setItem('selectedLabel', e); // 将label位置保存到localStorage中
        }
        
		// 选择行数据传递给父组件
		const handleSelectionChange = (rows) => {
		    selectedRows.value = rows;
		    emit('selected-rows', rows);
		}
        
        //将选中的设置背景颜色
        const tableRowStyle = ({ row }) => {
            let arr = [];
            if (selectedRows.value !== null) {
                selectedRows.value.filter((item, index) => {
                    arr.push(item.id);
                })
            }
            for (var i = 0; i < arr.length; i++) {
                if (arr[i] === row.id) {
                    return { backgroundColor: '#fcd3d3', fontSize: '13px' };
                }
            }
            return { fontSize: '13px' }; // 默认样式
        }
		
		watch(printDialogVisible, async (visible) => {
			if (visible) {
				await nextTick()
				if (!docxContainer.value) {
					docxContainer.value = document.querySelector('.docx-preview')
					console.warn('自动恢复容器引用:', docxContainer.value)
				}
			}
		})
		
        //联动下拉 visible-change下拉框出现/隐藏时触发
        const handleVisibleChange = async (visible, key) => {
            if (visible) {
                let id = props.bgsx.fields[key].kbtable;//联动表项目id
                let fh = props.bgsx.fields[key].kbcxcol;//返回列
                let max = Number(props.bgsx.fields[key].kbcxz);//总级数
                let now = Number(props.bgsx.fields[key].kbfhcol);//当前级
                if(id && fh && max > 1 && now && now <= max){
                    let values = {};//共支持5级下拉，如查第5级，需要传递1234级的key=>value
                    //遍历联动字段，查找联动级
                    const ldkeys = Object.keys(props.bgsx.fields).filter(key => props.bgsx.fields[key].type === 'linkselect');
                    for(let k of ldkeys) {
                        //不是最后一级时，要获取下级选项
                        if(props.bgsx.fields[k].kbfhcol < now) {
                            if(!formData[k]){
                                values = {};
                                break;//如果上级有空值，则禁止返回下级选项
                            }
                            let tempkey = props.bgsx.fields[k].kbcxcol;   //联动表中的查询列
                            values[tempkey] = formData[k];       //生成查询关联数组
                        }
                    }
                    //如果是第一级，或者有查询关联数组时，后端获取选项
                    if(now == 1 || Object.values(values).length > 0){
                        ldoptions.value[key] = await getldoptions({id, fh, max, now, values});
                    }
                }
            }
        }
        //联动选项变化，下级要清空
        const lxChange = (key) => {
            let now = Number(props.bgsx.fields[key].kbfhcol);//当前级
            const ldkeys = Object.keys(props.bgsx.fields).filter(key => props.bgsx.fields[key].type === 'linkselect');
            for(let k of ldkeys) {
                if(props.bgsx.fields[k].kbfhcol > now) {
                    console.log(k);
                    formData[k] = '';
                    ldoptions.value[k] = '';
                }
            }
        }
        
        //根据id获取用户名
        const cjzName = (id) => {
            if(!id) return '';
            const user = props.allusers.find(user => user.value == id);
            return user ? user.label : '';
        };
        
        const statusMap = { pending: '待审批', approved: '已通过', rejected: '已驳回', processing: '审批中' };
        //查看流程
        const viewapply = async (row) => {
            dialogApply.value = true
            const res = await getProcessDetail({
                formId: props.bgsx.id,
                rowid: row.id,
            })
            if(!res) return;
            
            // 构造步骤数据
            const maxStep = Math.max(...res.approvalRecords.map(r => r.step), res.currentStep)
            const steps = []
            for (let step = 1; step <= maxStep; step++) {
                const record = res.approvalRecords.find(r => r.step === step)
                steps.push({
                    step: step,
                    approver: record?.approver,
                    status: record?.status || 'pending'
                })
            }
            currentProcess.value = {
                ...res,
                steps: steps,
                // 添加申请人信息
                applicant: { name: res.initiator?.name || cjzName(row.cjz) },
                // 添加申请时间
                createdAt: row.created_at,
                // 按时间降序排列审批记录
                approvalRecords: [...res.approvalRecords].sort((b, a) => new Date(b.createdAt) - new Date(a.createdAt)),
                isend: 
                    // 情况1：存在驳回记录
                    res.approvalRecords.some(r => r.status === 'rejected') || 
                    // 情况2：已完成所有步骤（当前步骤超过配置步骤数）
                    (res.currentStep >= props.bgsx?.processConfig?.length) ||
                    // 情况3：实际步骤数超过配置步骤数（容错处理）
                    (maxStep > props.bgsx?.processConfig?.length)
            }
        }
        
        // 步骤状态计算
        const getStepStatus = (step) => {
            const currentStep = currentProcess.value.currentStep
             if (currentProcess.value.isend && currentProcess.value.approvalRecords.some(r => r.status === 'rejected')) {
                return 'error'
            }
            if (step.step < currentStep) return 'success'
            if (step.step === currentStep) return 'process'
            return 'wait'
        }
        
        // 记录标签类型
        const getRecordTagType = (status) => {
            switch(status) {
                case 'approved': return 'success'
                case 'rejected': return 'danger'
                case 'pending': return 'warning'
                default: return 'info'
            }
        }
        
        // 处理排序事件
        const handleSortChange = ({ prop, order }) => {
            // 系统保留字段映射表（前端维护）
            const SYSTEM_FIELDS = {'created_at': 'datetime','updated_at': 'datetime','id': 'number','cjz': 'number'};
            // 扩展类型映射
            const TYPE_MAP = {'number': 'number','date': 'date','datetime': 'datetime','mobile': 'number','idcard': 'text'};
            // 基础参数设置
            console.log(prop, order)
            sortParams.sortField = prop;
            sortParams.sortOrder = order ? (order === 'ascending' ? 'ASC' : 'DESC') : '';
            // 智能判断排序类型逻辑
            let sortType = 'text'; // 默认文本排序
            if (SYSTEM_FIELDS[prop]) {
                sortType = SYSTEM_FIELDS[prop];
            } else {
                const field = props.fields.find(f => f.prop === prop);
                if (field?.type) {
                    sortType = TYPE_MAP[field.type] || 'text';
                }
            }
            sortParams.sortType = sortType;
            emit('page-change', 1);
            emit('sort-change', sortParams);
        };
        
        // 列颜色
        const cellStyle = ({ column }) => {
            const k = column.property;
            if (!k) return {padding: '8px 0 !important'};
            const color = props.bgsx.fields[k]?.color?.trim().toLowerCase();
            // 无颜色或纯黑色时返回空对象
            if (!color || color === '#000000') return {padding: '8px 0 !important'}; 
            // 非黑色时设置加粗
            return {
                color: color,
                fontWeight: 700,
                padding: '8px 0 !important'
            };
        }
        
    	//显示地图
        const showMyMap = (string) => {
            if(!string)return;
            dialogmap.value = true;
            setTimeout(() => {
                let array = string.split(',');
                //定义地图中心点坐标
                var center = new TMap.LatLng(array[0],array[1])
                //定义map变量，调用 TMap.Map() 构造函数创建地图
                var map = new TMap.Map(document.getElementById('container'), {
                    center: center,//设置地图中心点坐标
                    zoom: 15,   //设置地图缩放级别
                    pitch: 43.5,  //设置俯仰角
                    rotation: 45    //设置地图旋转角度
                });
                //标记中心点
                var markerLayer = new TMap.MultiMarker({
                    map: map,
                    geometries: [{"id": "1","position": center}]
                });
            }, 500);
        }

        return {
            handleVisibleChange, getLocation, showMyMap, dialogmap, parsedValue,
            cellStyle,
            lxChange,
            ldoptions,
            tableRowStyle,
            labelfx,
            changelabel,
            getFileList,
            rowid,
            formRules,
            tableData,
            dialogVisible,
            dialogType,
            formRef,
            formData,
            handleAdd,
            handleEdit,
            handleDelete,
            submitForm,
            getComponentProps, getpath,
            handleBeforeUpload,
            handleUploadSuccess,
            handleRemove,
            scanIdCard,
            handleIdCardInput,
            extractIdCardInfo,
            getFieldType,
            handleUnlock,
            handlePageChange,
            handleSizeChange,
            jsonkeys,
            getColumnWidth,
            handleHeaderDragEnd,
            handlePrint,
            printDialogVisible,
            currentPrintContent,
            printType,
            printContent,
            doPrint,
            docxContainer,
            errorMessage,
            loading,
            isContentLoaded,
            validateContainer,
            selectedRows,
            ckzb,
            kbdata,
            dialogkb,
            kbcloums,
            handleSelectionChange,
            addRow,
            DeleteZd,
            datelx,
            user,
            cjzName,
            viewapply,
            dialogApply,
            currentProcess,
            statusMap,
            getStepStatus,
            getRecordTagType,
            handleSortChange, getFileName,
            sortParams,showUploadDialog,
            ckfwb,fwbtxt,dialogfwb, videourl, videoDialogVisible, videoPlayer,
            regionData: elementChinaAreaData.regionData,
        }
        
    },
    
    template: `
<el-dialog v-model="dialogmap" title="地图查看">
    <div id="container"></div>
</el-dialog>

<el-dialog title="预览视频" v-model="videoDialogVisible" top="2vh">
    <video ref="videoPlayer" controls width="100%" :style="{ maxHeight: 'calc(100vh - 100px)' }" :src="videourl" preload="auto" playsinline></video>
</el-dialog>

<el-table class="crudtabel" :data="tableData" border table-layout="auto" :header-cell-style="{'font-size': '13px', background: '#f9f9f9'}" :row-style="tableRowStyle" :cell-style="cellStyle" show-overflow-tooltip :row-key="(row) => row.id" @header-dragend.native="handleHeaderDragEnd" @selection-change="handleSelectionChange" @sort-change="handleSortChange">
    <el-table-column type="selection" width="55" :reserve-selection="true" fixed="left"></el-table-column>
    <el-table-column width="80" label="审核流程" align="center" fixed="left" v-if="bgsx.processConfig?.length">
        <template #default="scope">
            <el-button type="success" link @click="viewapply(scope.row)">查看</el-button>
        </template>
    </el-table-column>
    <el-table-column label="核销状态" align="center" fixed="left" v-if="bgsx.isReservation && bgsx.enableVerification">
        <template #default="{row}">
            <el-tag :type="row.used ? 'success' : 'warning'">
                {{ row.used ? '已核销' : '待核销' }}
            </el-tag>
        </template>
    </el-table-column>
	<!-- 动态数据列 -->
	<template v-for="col in columns" :key="col.prop">
		<el-table-column :prop="col.prop" :label="col.label" :width="getColumnWidth(col)" :sortable="bgsx.pxzd?.includes(col.prop) ? 'custom' : false" v-if="viewcolum.includes(col.prop)">
            <template #header="{ column }">
                <el-tooltip v-if="column.label && column.label.length > 4" :content="column.label">
                    <div class="ellipsis-text">{{ column.label }}</div>
                </el-tooltip>
                <template v-else>{{ column.label }}</template>
            </template>
			<template #default="scope">
				<!-- 根据字段类型显示不同内容 -->
				<template v-if="getFieldType(col) === 'multiimage'">
					<div class="image-container">
						<template v-if="$validators.isJSON(scope.row[col.prop])">
							<el-image v-for="(img, idx) in JSON.parse(scope.row[col.prop])" :key="idx" :src="img"
								:preview-src-list="JSON.parse(scope.row[col.prop])" fit="cover" style="height:60px">
								<template #error>
									<div class="image-error">加载失败</div>
								</template>
							</el-image>
						</template>
					</div>
				</template>

				<template v-else-if="['muselect', 'checkbox', 'area'].includes(getFieldType(col))">
					<span>{{ parsedValue(scope.row[col.prop], getFieldType(col)) }}</span>
				</template>

				<template v-else-if="getFieldType(col) == 'image'">
					<el-image v-if="scope.row[col.prop]" :src="scope.row[col.prop]" style="height:60px;" :preview-src-list="[scope.row[col.prop]]" fit="cover">
						<template #error>
							<div class="image-error">图片加载失败</div>
						</template>
					</el-image>
				</template>
				
				<template v-else-if="getFieldType(col) == 'sczs'">
				    <div class="print-container" v-if="scope.row[col.prop]">
                        <el-image :src="scope.row[col.prop]" style="height:60px;" :preview-src-list="[scope.row[col.prop]]" fit="cover">
                        	<template #error>
                        		<div class="image-error">图片加载失败</div>
                        	</template>
                        </el-image>
                        <el-button size="small" @click="handlePrint(scope.row[col.prop], 'image')" class="print-button">
                            <el-icon><Printer /></el-icon>打印
                        </el-button>
                    </div>
				</template>

				<template v-else-if="getFieldType(col) === 'word'">
				    <div class="print-container" v-if="scope.row[col.prop]">
                    	<el-link type="primary" :href="scope.row[col.prop]" target="_blank" :underline="false">
                    		<el-icon><Document /></el-icon>下载文档
                    	</el-link>
                    	<el-button size="small" @click="handlePrint(scope.row[col.prop], 'word')" class="print-button">
                    	    <el-icon><Printer /></el-icon>打印
                    	</el-button>
    				</div>
				</template>
				
				<template v-else-if="getFieldType(col) === 'file'">
				    <div class="print-container" v-if="scope.row[col.prop]">
                    	<el-link type="primary" :href="scope.row[col.prop]" target="_blank" :underline="false">
                    		{{getFileName(scope.row[col.prop])}}
                    	</el-link>
    				</div>
				</template>
				
				<template v-else-if="getFieldType(col) === 'multifile'">
					<div class="print-container" v-if="$validators.isJSON(scope.row[col.prop])">
						<div v-for="(src, idx) in JSON.parse(scope.row[col.prop])" :key="idx">
    						<el-link type="primary" :href="src" target="_blank" :underline="false">
                        		{{getFileName(src)}}
                        	</el-link>
						</div>
					</div>
				</template>
				
				<template v-else-if="getFieldType(col) == 'date'">
					{{ $validators.formatDate(scope.row[col.prop], 'YYYY-MM-DD') }}
				</template>
				
				<!-- 子表 -->
				<template v-else-if="getFieldType(col) == 'subtable' && $validators.isJSON(scope.row[col.prop])">
					<el-button type="primary" v-if="JSON.parse(scope.row[col.prop]).length > 0" link size="small" @click="ckzb(col.prop, scope.row[col.prop])">查看内容</el-button>
				</template>
				
				<!-- 地图 -->
				<template v-else-if="getFieldType(col) == 'map' && scope.row[col.prop]">
					<el-button type="primary" link size="small" @click="showMyMap(scope.row[col.prop])">查看</el-button>
				</template>
				
				<!-- 视频 -->
				<template v-else-if="getFieldType(col) == 'video' && $validators.isJSON(scope.row[col.prop])">
				    <div v-for="item in JSON.parse(scope.row[col.prop])">
    					<el-button type="primary" v-if="item" link size="small" @click="videourl = item; videoDialogVisible = true;">查看</el-button>
					</div>
				</template>
				
				<!-- 富文本 -->
				<template v-else-if="getFieldType(col) == 'richtext' && scope.row[col.prop]">
					<el-button type="primary" link size="small" @click="ckfwb(scope.row[col.prop])">查看内容</el-button>
				</template>
				
    			<!-- 锁定状态列 -->
    			<template v-else-if="col.type === 'is_locked'">
    				<el-tag v-if="scope.row.is_locked === 1" type="info" effect="dark" @click="handleUnlock(scope.row.id)"
    					class="lock-tag">解锁</el-tag>
    				<el-tag v-else type="success" effect="plain">未锁定</el-tag>
    			</template>
    
    			<!-- 查询次数列 -->
    			<template v-else-if="col.type === 'query_count'">
    				{{ scope.row.query_count }}
    			</template>

				<template v-else>
					{{ scope.row[col.prop] !== '[]' ? scope.row[col.prop] : '' }}
				</template>
			</template>
		</el-table-column>
	</template>
	<el-table-column prop="cjz" label="填报人" :width="100" v-if="user.Role == 'admin' && allusers.length && viewcolum.includes('cjz')" sortable="custom">
        <template #default="scope">
            <span>{{ cjzName(scope.row.cjz) || scope.row.cjz }}</span>
        </template>
    </el-table-column>
    <el-table-column prop="created_at" label="创建时间" :width="180" v-if="viewcolum.includes('created_at')" sortable="custom">
        <template #default="scope">
            <span>{{ $validators.formatDate(scope.row.created_at)}}</span>
        </template>
    </el-table-column>
	<el-table-column label="操作" width="150" fixed="right">
		<template #default="scope">
			<el-button size="small" @click="handleEdit(scope.row)">编辑</el-button>
			<el-button size="small" type="danger" @click="handleDelete(scope.row)">删除</el-button>
		</template>
	</el-table-column>
</el-table>
<!-- 分页区 -->
<el-pagination background :current-page="pagination.page" :page-sizes="pagination.sizes" :page-size="pagination.size" :layout="pagination.layout" :total="pagination.total" @size-change="handleSizeChange" @current-change.sync="handlePageChange" />

<!-- 表单弹窗 -->
<el-dialog v-model="dialogVisible" :title="dialogType === 'add' ? '新增数据' : '修改数据'" width="70%">
    <el-row style="margin:0 0 10px 0;">
        <el-button type="primary" link @click="changelabel('left')">标题居左</el-button>
        <el-button type="warning" link @click="changelabel('right')">标题居右</el-button>
        <el-button type="success" link @click="changelabel('top')">标题居上</el-button>
    </el-row>
	<el-form ref="formRef" :model="formData" label-width="100px" :rules="formRules" :label-position="labelfx" style="padding:10px">
		<template v-for="field in fields" :key="field.prop">
			<!-- 动态表单项 -->
			<el-form-item :label="field.label" :prop="field.prop" style="width:100%;">
					<!-- 下拉选择 -->
					<template v-if="['select', 'muselect'].includes(field.type)">
						<el-select v-model="formData[field.prop]" :multiple="field.type === 'muselect'" v-bind="getComponentProps(field)">
							<el-option v-for="opt in field.options" :key="opt.value" :label="opt.label"
								:value="opt.value" />
						</el-select>
					</template>

					<!-- 单选框组 -->
					<template v-else-if="field.type === 'radio'">
						<el-radio-group v-model="formData[field.prop]" v-bind="getComponentProps(field)">
							<el-radio v-for="opt in field.options" :key="opt.value" :label="opt.value">
								{{ opt.label }}
							</el-radio>
						</el-radio-group>
					</template>

					<!-- 多选框组 -->
					<template v-else-if="field.type === 'checkbox'">
						<el-checkbox-group v-model="formData[field.prop]" v-bind="getComponentProps(field)">
							<el-checkbox v-for="opt in field.options" :key="opt.value" :label="opt.value">
								{{ opt.label }}
							</el-checkbox>
						</el-checkbox-group>
					</template>

					<!-- 日期选择 -->
					<template v-else-if="field.type === 'date'">
						<el-date-picker v-model="formData[field.prop]" v-bind="getComponentProps(field)" />
					</template>

					<!-- 日期时间选择 -->
					<template v-else-if="field.type === 'datetime'">
						<el-date-picker v-model="formData[field.prop]" v-bind="getComponentProps(field)" />
					</template>
					
					<!-- 时间选择 -->
					<template v-else-if="field.type === 'time'">
						<el-time-picker v-model="formData[field.prop]" v-bind="getComponentProps(field)" />
					</template>
					
                    <!-- 随机密钥、行内计算、字符拼接 -->
                    <template v-else-if="['randomkey','rowcalc', 'stringconcat'].includes(field.type)">
                    	<el-input v-model="formData[field.prop]" v-bind="getComponentProps(field)"></el-input>
                    </template>

					<!-- 身份证输入（带扫描按钮） -->
					<template v-else-if="field.type === 'idcard'">
						<el-input v-model="formData[field.prop]" @input="(v) => handleIdCardInput(v, field.prop)" :maxlength="18" show-word-limit v-bind="getComponentProps(field)">
							<template #append>
								<el-button @click="scanIdCard(field.prop)">
									<el-icon>
										<Camera />
									</el-icon>
								</el-button>
							</template>
						</el-input>
					</template>

					<!-- 数字输入 -->
					<template v-else-if="field.type === 'number'">
						<el-input v-model="formData[field.prop]" v-bind="getComponentProps(field)" />
					</template>

					<!-- 多行文本 -->
					<template v-else-if="field.type === 'textarea'">
						<el-input v-model="formData[field.prop]" v-bind="getComponentProps(field)" />
					</template>
					
					<!-- 富文本 -->
					<template v-else-if="field.type === 'richtext'">
						<uniedit v-model="formData[field.prop]" v-bind="getComponentProps(field)" />
					</template>
					
                    <!--联动下拉-->
                    <template v-else-if="field.type === 'linkselect'">
                    	<el-select v-model="formData[field.prop]" @visible-change="handleVisibleChange($event, field.prop)" @change="lxChange(field.prop)" clearable :placeholder="field.placeholder" v-bind="getComponentProps(field)">
                    		<el-option v-for="option in ldoptions[field.prop]" :key="option" :label="option" :value="option"></el-option>
                    	</el-select>
                    </template>
                    
                    <!--省市县联动-->
                    <template v-else-if="field.type == 'area'">
                        <el-cascader style="width:100%;" filterable v-model="formData[field.prop]" :options="regionData" clearable :props="{value: 'label',label: 'label'}" :placeholder="field.placeholder" v-bind="getComponentProps(field)"></el-cascader>
                    </template>

					<!-- 子表 -->
					<template v-else-if="field.type === 'subtable'">
						<el-table v-if="formData[field.prop] && Array.isArray(formData[field.prop])" :data="formData[field.prop]" border table-layout="auto" :header-cell-style="{'font-size': '14px', background: '#f9f9f9'}" style="width:100%;">
							<el-table-column v-for="(col, index) in field.zboptions" :key="index" :prop="col.key" :label="col.key" min-width="160px">
								<template #default="scope">
									<template v-if="col.lx && formData[field.prop][scope.$index]">
										<el-input v-if="col.lx === 'text'" v-model="formData[field.prop][scope.$index][col.key]" clearable :placeholder="col.key" style="width:100%"></el-input>

										<el-input v-else-if="col.lx === 'textarea'" type="textarea" autosize v-model="formData[field.prop][scope.$index][col.key]" :placeholder="col.key" style="width:100%"></el-input>

										<el-input v-else-if="col.lx === 'number'" v-model="formData[field.prop][scope.$index][col.key]" type="number" clearable :placeholder="col.key" style="width:100%"></el-input>

										<el-select v-else-if="col.lx === 'select'" v-model="formData[field.prop][scope.$index][col.key]"  clearable filterable :placeholder="col.key" style="min-width:200px;">
											<el-option v-for="option in col.xx.split('/')" :key="option" :label="option" :value="option"></el-option>
										</el-select>

										<el-date-picker v-else-if="col.lx == 'date' || col.lx == 'datetime'" v-model="formData[field.prop][scope.$index][col.key]" :type="col.lx" :format="datelx[col.lx].format" :value-format="datelx[col.lx].valueFormat" :placeholder="col.key" style="width:100%"></el-date-picker>

										<el-input v-else-if="col.lx === 'mobile'" type="number" min="13000000000" max="19999999999" v-model="formData[field.prop][scope.$index][col.key]" :placeholder="col.key" style="width:100%"></el-input>

										<el-input v-else-if="col.lx === 'idcard'" v-model="formData[field.prop][scope.$index][col.key]" :placeholder="col.key" style="width:100%">
										</el-input>
								   </template>
								</template>
							</el-table-column>>
							<el-table-column fixed="right" label="操作" width="120">
								<template #default="scope">
								   <el-button link type="danger" @click="DeleteZd(scope.$index, field.prop)">删除</el-button>
								</template>
							</el-table-column>
						</el-table>
						<el-button type="primary" size="small" @click="addRow(field.prop, field.zboptions)">添加一行</el-button>
					</template>
					
                    <!-- word模板 -->
                	<template v-else-if="field.type === 'word'">
                        <a v-if="formData[field.prop]" :href="formData[field.prop]" class="word-link" target="_blank">查看/下载Word</a>
                    </template>
                    
                    <!--地图定位-->
                    <template v-else-if="field.type == 'map'">
                        <el-input v-model="formData[field.prop]" disabled :placeholder="field.placeholder"></el-input>
                        <el-button v-if="formData[field.prop]" @click="showMyMap(formData[field.prop])">查看</el-button>
                        <el-button v-else @click="getLocation(field.prop, formData)">获取位置</el-button>
                    </template>

                    <!-- 图片上传 -->
                    <template v-else-if="['image', 'multiimage', 'sczs'].includes(field.type)">
                        <el-upload :file-list="getFileList(field)" v-bind="getComponentProps(field)" :before-upload="(file)=>handleBeforeUpload(file, field)" :on-success="(res)=>handleUploadSuccess(res, field)" :on-remove="(file)=>handleRemove(file, field)"><el-icon><Plus /></el-icon>
                    	</el-upload>
                    </template>
                    
                    <!-- 附件上传单独传参 -->
                    <div v-else-if="['file', 'multifile', 'video'].includes(field.type)">
                        <el-button type="success" plain @click="showUploadDialog[field.prop] = true"><el-icon><Upload /></el-icon>上传文件</el-button>&nbsp;
                        <div>
                            <template v-if="formData[field.prop]">
                                <div v-if="field.type === 'file'" class="attachment-item">
                                    <span class="file-name2">{{ getFileName(formData[field.prop]) }}</span>
                                    <el-icon class="delete-icon" @click="handleRemove(formData[field.prop], field)"><Close /></el-icon>
                                </div>
                                <template v-else>
                                    <div v-for="(url, index) in formData[field.prop]" :key="index" class="attachment-item">
                                        <span class="file-name2">{{ getFileName(url) }}</span>
                                        <el-icon class="delete-icon" @click="handleRemove(index, field)"><Close /></el-icon>
                                    </div>
                                </template>
                            </template>
                        </div>
                        <UploadDialog v-model="showUploadDialog[field.prop]" :current-path="getpath()" @success="(url) => handleUploadSuccess(url, field)"/>
                    </div>
                    
					<!-- 默认文本输入 -->
					<template v-else>
						<el-input v-model="formData[field.prop]" v-bind="getComponentProps(field)" />
					</template>
			</el-form-item>
		</template>
		<el-form-item label="填报人" placeholder="请选择填报人" prop="cjz" v-if="user.Role == 'admin' && allusers.length">
			<el-select v-model="formData.cjz">
				<el-option  v-for="item in allusers" :key="item.value" :label="item.label" :value="item.value" />
			</el-select>
		</el-form-item>
        <el-row justify="center">
            <el-col :span="8" style="text-align: center;margin: 20px;">
                <el-button type="primary" size="large" style="margin-right:20px" @click="submitForm">确认</el-button>
                <el-button @click="dialogVisible = false" size="large">取消</el-button>
            </el-col>
		</el-row>
	</el-form>
</el-dialog>

<!-- 打印弹窗 -->
<el-dialog v-model="printDialogVisible" title="打印预览" class="print-preview-dialog" :append-to-body="true" :destroy-on-close="false">
	<div ref="printContent" v-loading="loading">
		<!-- 图片预览 -->
		<img v-if="printType === 'image'" :src="currentPrintContent" style="max-width: 100%" />
		<!-- Word文档预览 -->
		<div v-if="printType === 'word'" ref="docxContainer" class="docx-preview"></div>
		<!-- 加载状态 -->
		<div v-if="loading" class="loading-wrapper">
			<el-icon class="is-loading" size="24"><Loading /></el-icon>
			<span>文档加载中...</span>
		</div>
		<!-- 错误提示 -->
		<div v-if="errorMessage" class="error-message">
			<el-alert :title="errorMessage" type="error" />
		</div>
	</div>
	<template #footer>
		<el-button @click="printDialogVisible = false">取消</el-button>
		<el-button type="primary" @click="doPrint" :disabled="!isContentLoaded">
			立即打印
		</el-button>
	</template>
</el-dialog>

<!-- 查看子表弹窗 -->
<el-dialog v-model="dialogkb" title="查看子表数据" width="65%" v-if="Object.keys(kbcloums).length > 0 && kbdata.length > 0">
    <div style="height: 400px">
        <el-table :data="kbdata" max-height="550" table-layout="auto" :header-cell-style="{'font-size': '14px',background:'#eff6fa'}" :row-style="{'font-size':'13px'}" border>
            <template v-for="(v, k) in kbcloums" :key="k">
                <el-table-column :label="v">
                    <template #default="{ row }">
                        <div v-if="typeof row[k] === 'string' && $validators.isJSON(row[k])">多图隐藏</div>
                        <div v-else-if="typeof row[k] === 'string' && $validators.isImageUrl(row[k])">
                            <el-image style="max-width: 80px;height: 30px;" :src="row[k]" :preview-src-list="[row[k]]"></el-image>
                        </div>
                        <div v-else-if="typeof row[k] === 'string' && row[k].startsWith('http')">
                            <a :href="row[k]" target="_blank" rel="noopener noreferrer">{{ $t('download') }}</a>
                        </div>
                        <div v-else>
                            <span>{{ row[k] }}</span>
                        </div>
                    </template>
                </el-table-column>
            </template>
        </el-table>
    </div>
</el-dialog>

<!-- 查看富文本弹窗 -->
<el-dialog v-model="dialogfwb" title="查看内容">
    <div v-html="fwbtxt"></div>
</el-dialog>

<!-- 流程状态弹窗 -->
<el-dialog v-model="dialogApply" title="流程审核状态" width="60%">
    <div>
        <!-- 审批步骤 -->
        <el-steps :active="currentProcess.currentStep + 1" align-center>
            <!-- 添加发起人作为第一步 -->
            <el-step
                title="发起人"
                :description="currentProcess.applicant?.name || '申请人'"
                status="success"
            />
            <el-step 
                v-for="(step, index) in currentProcess.steps"
                :key="index"
                :title="'步骤' + (index + 1)"
                :description="step.approver?.name || '未指定审批人'"
                :status="getStepStatus(step)"
            />
        </el-steps>

        <!-- 审批记录 -->
        <el-divider content-position="left">审批记录</el-divider>
        <el-timeline>
            <!-- 发起人提交记录 -->
            <el-timeline-item :timestamp="$validators.formatDate(currentProcess.createdAt)" placement="top">
                <el-tag type="success">发起</el-tag>
                <span class="approver">{{ currentProcess.applicant?.name }}</span>
            </el-timeline-item>

            <!-- 审批记录 -->
            <el-timeline-item v-for="(record, index) in currentProcess.approvalRecords":key="index" placement="top"
                :timestamp="record.status === 'pending' ? '' : $validators.formatDate(record.createdAt)">
                <el-tag :type="getRecordTagType(record.status)">{{ statusMap[record.status] }}</el-tag>
                <span class="approver">{{ record.approver?.name || '系统自动' }}</span>
                <div v-if="record.comment" class="comment">{{ record.comment }}</div>
                <div v-else class="no-comment"></div>
            </el-timeline-item>

            <el-timeline-item placement="top" v-if="currentProcess.isend">已结束</el-timeline-item>
        </el-timeline>
    </div>
</el-dialog>
`
}